/**
 * XML转换器
 */
function sXMLConvertor(){
    var parser = new DOMParser();
    
    /**
     * 字体大小本地像素转换比
     */
    var ratioFONT = 1;

    /**
     * px单位本地像素转换比
     */
    var ratioPX = 1;

    /**
     * pt单位本地像素转换比
     */
    var ratioPT = 1;

    /**
     * cm单位本地像素转换比
     */
    var ratioCM = 1;

    /**
     * 设置外部单位和本地单位的转换比
     * @param {*} opt
     * 
     */
    this.setScale = function(opt){
        if(!opt) return;

        ratioFONT = opt.scale_font;
        ratioPX = opt.scale_px;
        ratioPT = opt.scale_pt;
        ratioCM = opt.scale_cm;
    }

    /**
     * 解析XML
     * @param {*} xml 
     */
    this.parseXML = function(xml){
        try{
            var xmlDoc = parser.parseFromString(xml, "text/xml");
            var root = {_sType: "sRoot", children:[]};

            parseArea(xmlDoc, root);

            return root;
        }catch(e){
            console.error(e);
            return null;
        }
    }

    /**
     * 解析文档分区
     * @param {*} node 
     * @param {*} parentNode 
     */
    var parseArea = function(node, parentNode){
        let pNode = null;

        if(node.tagName == "XElements"){
            for(let i = 0; i < node.children.length; i++){
                parseArea(node.children[i], pNode ? pNode : parentNode);
            }
            return;
        } 
        
        if(node.tagName == "Element"){
            if(node.getAttribute("xsi:type") == "XTextHeader"){
                pNode = {
                    _sType: "sPageHead",
                    children: []
                };
            }else if(node.getAttribute("xsi:type") == "XTextBody"){
                pNode = {
                    _sType: "sPageBody",
                    children: []
                };
            }else if(node.getAttribute("xsi:type") == "XTextFooter"){
                pNode = {
                    _sType: "sPageFoot",
                    children: []
                };
            }
        }else if(node.tagName == "FileName"){
        }else if(node.tagName == "ContentStyles"){
            parseContentStyle(node, parentNode);
        }else if(node.tagName == "PageSettings"){
            parsePageSetting(node, parentNode);
        }

        if(pNode){
            parentNode.children.push(pNode);
        }

        for(let i = 0; i < node.children.length; i++){
            if(pNode){
                parseNode(node.children[i], pNode);
            }else{
                parseArea(node.children[i], parentNode);
            }
        }
    }

    /**
     * 解析元素节点
     * @param {*} node 
     * @param {*} parentNode 
     * @param {*} element
     */
    var parseNode = function(node, parentNode, element){
        if(node.tagName == "XElements"){
            for(let i = 0; i < node.children.length; i++){
                parseNode(node.children[i], parentNode, element);
            }
            return;
        }

        let pNode = null;

        if(node.tagName == "Element"){
            if(node.getAttribute("xsi:type") == "XTextTable"){
                let table = {
                    _sType: "sTable",
                    columns: [],
                    rows: []
                };

                parentNode.children.push(table);
                parseChildren(node, table, parentNode);
                setDisplay(table, element);

                return;
            }else if(node.getAttribute("xsi:type") == "XTextTableRow"){
                let row = {
                    _sType: "sTableRow",
                    cells: []
                };

                parentNode.rows.push(row);
                parseChildren(node, row, parentNode);

                return;
            }else if(node.getAttribute("xsi:type") == "XTextTableCell"){
                let cell = {
                    _sType: "sTableCell",
                    rowspan: 1,
                    colspan: 1,
                    children: []
                };

                setStyleIndex(cell, node);

                parentNode.cells.push(cell);
                parseChildren(node, cell, parentNode);

                return;
            }else if(node.getAttribute("xsi:type") == "XTextTableColumn"){
                let column = {
                    _sType: "sTableColumn",
                    style: {}
                };

                parentNode.columns.push(column);
                parseChildren(node, column, parentNode);
                
                return;
            }else if(node.getAttribute("xsi:type") == "XImage"){
                let image = {
                   _sType: "sImage",
                   style: {}
                };
                let layer = {
                    _sType: "sLayer",
                    children: [image],
                    style: {}
                };

                setStyleIndex(layer, node);

                parentNode.children.push(layer);
                parseChildren(node, image, parentNode);
                setDisplay(layer, element);

                layer.$width = image.style.width;
                layer.$height = image.style.height;

                return;
            }else if(node.getAttribute("xsi:type") == "XString"){
                let text = {
                    _sType: "sText",
                    innerText: ""
                };
                
                setStyleIndex(text, node);
                setDisplay(text, element);

                parentNode.children.push(text);
                pNode = text;
            }else if(node.getAttribute("xsi:type") == "XParagraphFlag"){
                let paragraph = {
                    _sType: "sParagraph"
                };

                setStyleIndex(paragraph, node);
                setDisplay(paragraph, element);

                parentNode.children.push(paragraph);
                pNode = paragraph;
            }else if(node.getAttribute("xsi:type") == "HorizontalLine"){
                let line = {
                    _sType: "sLayer",
                    presentType: "line"
                };

                parseLine(node, line);
                setStyleIndex(line, node);
                setDisplay(line, element);

                parentNode.children.push(line);
                pNode = line;
            }else if(parseComplexNode(node, parentNode, element)){
                return;
            }
        }else if(node.tagName == "Text"){
            parentNode.innerText = node.textContent;
        }else if(node.tagName == "RowSpan"){
            parentNode.rowspan = parseInt(node.textContent);
        }else if(node.tagName == "ColSpan"){
            parentNode.colspan = parseInt(node.textContent);
        }else if(node.tagName == "Image"){
            let base64 = getImageData(node);
            parentNode.src = "data:image/jpg;base64," + base64;
        }else if(node.tagName == "Width"){
            if(!parentNode.style){
                parentNode.style = {};
            }
            parentNode.style.width = parseFloat(node.textContent) / ratioPT;
        }else if(node.tagName == "Height"){
            if(!parentNode.style){
                parentNode.style = {};
            }
            parentNode.style.height = parseFloat(node.textContent) / ratioPT;
        }else if(node.tagName == "Visible"){
            if(node.textContent == "false"){
                if(!parentNode.style){
                    parentNode.style = {};
                }
                parentNode.style.display = "none";
            }
        }

        parseChildren(node, pNode, parentNode, element);
    }

    /**
     * 解析子节点
     * @param {*} node 
     * @param {*} pNode 
     * @param {*} parentNode 
     * @param {*} element
     */
    var parseChildren = function(node, pNode, parentNode, element){
        for(let i = 0; i < node.children.length; i++){
            parseNode(node.children[i], pNode ? pNode : parentNode, element);
        }
    }

    /**
     * 分析dom节点的可见性设置对应元素
     * @param {*} domNode 
     * @param {*} element 
     */
    var setDisplayByDomNode = function(domNode, element){
        for(let i = 0; i < domNode.children.length; i++){
            if(domNode.children[i].tagName != "Visible") continue;
            if(domNode.children[i].textContent.trim() == "false"){
                element.$display = "none";
            }
        }
    }

    /**
     * 设置显示状态
     * @param {*} node 
     * @param {*} element 
     */
    var setDisplay = function(node, element){
        if(element && element.$display){
            node.$display = element.$display;
        }
    }

    /**
     * 设置样式序号
     * @param {*} element 
     * @param {*} node 
     */
    var setStyleIndex = function(element, node){
        let styleIndex = node.getAttribute("StyleIndex");
        if(styleIndex != null){
            element.style = "style_" + styleIndex;
        }
    }

    /**
     * 获取图片节点的base64编码
     * @param {*} node 
     * @returns 
     */
    var getImageData = function(node){
        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].tagName == "ImageDataBase64String"){
                return node.children[i].textContent;
            }
        }
        return "";
    }
    
    /**
     * 解析直线
     * @param {*} node 
     * @param {*} element 
     */
    var parseLine = function(node, element){
        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].tagName == "LineSize"){
                element.$lineWidth = parseFloat(node.children[i].textContent);
                element.$height = parseFloat(node.children[i].textContent);    
            }else if(node.children[i].tagName == "LineLengthInCM"){
                element.$width = parseFloat(node.children[i].textContent) * ratioCM;
            }
        }

        element.$display = "inline-block";
        element.$lineWidth = element.$lineWidth ? element.$lineWidth : 1;
        element.$lineDash = element.$lineDash ? element.$lineDash : null;
    }

    /**
     * 处理复杂节点
     * @param {*} node 
     * @param {*} parentNode 
     * @param {*} element
     */
    var parseComplexNode = function(node, parentNode, element){
        let type = node.getAttribute("xsi:type");
        if(type == "XInputField"){
            let beginNode = {
                _sType: "sInputBegin",
                attributes: {}
            };

            let textNode = {
                _sType: "sText"
            };

            parentNode.children.push(beginNode);

            setDisplay(beginNode, element);
            setDisplayByDomNode(node, beginNode);
            setStyleIndex(beginNode, node);
            setStyleIndex(textNode, node);
            
            let hasXElement = parseComplexElements(node, beginNode, parentNode, (subNode, element)=>{
                if(subNode.tagName == "InnerValue"){
                    textNode.innerText = subNode.textContent;
                }else if(subNode.tagName == "BackgroundText"){
                    textNode.innerText = subNode.textContent;
                    element.attributes.backgroundtext = subNode.textContent;
                }
            });

            if(beginNode.attributes.dropdowntype){
                textNode.placeholder = textNode.innerText;
                textNode.innerText = "";
            }

            if(!hasXElement){
                parentNode.children.push(textNode);
                setDisplay(textNode, beginNode);
            }

            let endNode = {
                _sType: "sInputEnd",
                attributes: {}
            };

            setDisplay(endNode, beginNode);

            parentNode.children.push(endNode);

            return true;
        }else if(type == "XTextCheckBox" || type == "XTextRadioBox"){
            let isCheckBox = type == "XTextCheckBox";
            let checkbox = {
                _sType: isCheckBox ? "sCheckBox" : "sRadio",
                style: {},
                attributes: {}
            };

            let layer = {
                _sType: "sLayer",
                presentType: isCheckBox ? "checkbox" : "radio",
                style: {},
                children: [checkbox]
            };
            
            parentNode.children.push(layer);

            setDisplay(layer, element);
            setDisplayByDomNode(node, layer);
            setStyleIndex(layer, node);

            parseComplexElements(node, checkbox, parentNode, (subNode)=>{
                if(subNode.tagName == "Width"){
                    checkbox.style.width = parseFloat(subNode.textContent) / ratioPT - 5;
                }else if(subNode.tagName == "Height"){
                    checkbox.style.height = parseFloat(subNode.textContent) / ratioPT - 5;
                }else if(subNode.tagName == "Checked"){

                }else if(subNode.tagName == "CheckedValue"){
                    
                }else if(subNode.tagName == "GroupName"){
                    // checkbox.title = subNode.textContent;
                    checkbox.name = subNode.textContent;
                }else if(subNode.tagName == "Caption"){
                    checkbox.title = subNode.textContent;
                }
            });

            if(!checkbox.title){
                checkbox.title = "";
            }

            layer.$width = checkbox.style.width;
            layer.$height = checkbox.style.height;
        }

        return false;
    }

    /**
     * 解析复杂节点的属性和子节点
     * @param {*} node 
     * @param {*} element 
     * @param {*} textElement 
     * @param {*} parentNode 
     * @returns 
     */
    var parseComplexElements = function(node, element, parentNode, callback){
        let hasXElement = false;
        let subNode = null;

        for(let i = 0; i < node.children.length; i++){
            subNode = node.children[i];
            
            if(subNode.tagName == "ID"){
                element.id = subNode.textContent;
                element.attributes.id = subNode.textContent;
            }else if(subNode.tagName == "Name"){
                element.name = subNode.textContent;
                element.attributes.name = subNode.textContent;
            }else if(subNode.tagName == "ContentReadonly"){
                element.attributes.readonly = subNode.textContent == "True";
            }else if(subNode.tagName == "ValueBinding"){
                parseValueBinding(subNode, element);
            }else if(subNode.tagName == "XElements"){
                for(let j = 0; j < subNode.children.length; j++){
                    parseNode(subNode.children[j], parentNode, element);
                }
                hasXElement = subNode.children.length > 0;
            }else if(subNode.tagName == "FieldSettings"){
                parseFieldSettings(subNode, element);
            }else if(subNode.tagName == "DisplayFormat"){
                parseDisplayFormat(subNode, element);
            }else if(callback){
                callback(subNode, element);
            }
        }

        return hasXElement;
    }

    /**
     * 解析绑定值
     * @param {*} node 
     * @param {*} element 
     */
    var parseValueBinding = function(node, element){
        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].tagName == "DataSource"){
                element.attributes.datasourcename = node.children[i].textContent;
            }else if(node.children[i].tagName == "BindingPath"){
                element.attributes.datasourcefield = node.children[i].textContent;
            }
        }
    }

    /**
     * 解析字段设置
     * @param {*} node 
     * @param {*} element 
     */
    var parseFieldSettings = function(node, element){
        let child = null;
        let subChild = null;

        for(let i = 0; i < node.children.length; i++){
            child = node.children[i];

            if(child.tagName == "EditStyle"){
                if(child.textContent.indexOf("Date") > -1){
                    element.attributes.dropdowntype = "calendar";
                }else if(child.textContent == "DropdownList"){
                    element.attributes.dropdowntype = "list";
                }
            }else if(child.tagName == "ListSource"){
                element.attributes.list = [];
                parseListSource(child, element.attributes.list);
            }else if(child.tagName == "DisplayFormat"){
                parseDisplayFormat(child, element);
            }
        }
    }

    /**
     * 解析ListSource
     * @param {*} node 
     * @param {*} list 
     */
    var parseListSource = function(node, list){
        let child = null;
        let subChild = null;

        for(let i = 0; i < node.children.length; i++){
            child = node.children[i];
            for(let j = 0; j < child.children.length; j++){
                subChild = child.children[j];
                let item = {};
                for(let k = 0; k < subChild.children.length; k++){
                    if(subChild.children[k].tagName == "Text"){
                        item.display = subChild.children[k].textContent;
                    }else if(subChild.children[k].tagName == "Value"){
                        item.value = subChild.children[k].textContent;
                    }
                }
                list.push(item);
            }
        }
    }

    /**
     * 解析显示格式
     * @param {*} node 
     * @param {*} element 
     */
    var parseDisplayFormat = function(node, element){
        let child = null;
        for(let j = 0; j < node.children.length; j++){
            child = node.children[j];
            if(child.tagName == "Style"){
                element.attributes.viewMode = child.textContent.toLowerCase();
            }else if(child.tagName == "Format"){
                element.attributes.valueFormat = child.textContent;
            }
        }
    }

    /**
     * 解析内容样式
     * @param {*} node 
     * @param {*} parentNode 
     */
    var parseContentStyle = function(node, parentNode){
        if(!parentNode.styles){
            parentNode.styles = [];
        }

        let child = null;
        let children = null;
        let subChildren = null;
        let style = null;
        let temp = null;

        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].tagName == "Default"){

            }else if(node.children[i].tagName == "Styles"){
                child = node.children[i];
                for(let j = 0; j < child.children.length; j++){
                    children = child.children[j];
                    style = {};
                    temp = {};
                    for(let k = 0; k < children.children.length; k++){
                        subChildren = children.children[k];
                        parseStyle(subChildren, style, temp);
                    }
                    parentNode.styles.push(style);
                }
            }
        }
    }

    /**
     * 解析页面设置
     * @param {*} node 
     * @param {*} parentNode 
     */
    var parsePageSetting = function(node, parentNode){
        if(!parentNode.style){
            parentNode.style = {};
        }
        
        if(!parentNode.style.padding){
            parentNode.style.padding = {};
        }

        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].tagName == "LeftMargin"){
                parentNode.style.padding.left = parseFloat(node.children[i].textContent);
            }else if(node.children[i].tagName == "RightMargin"){
                parentNode.style.padding.right = parseFloat(node.children[i].textContent);
            }else if(node.children[i].tagName == "TopMargin"){
                parentNode.style.padding.top = parseFloat(node.children[i].textContent);
            }else if(node.children[i].tagName == "BottomMargin"){
                parentNode.style.padding.bottom = parseFloat(node.children[i].textContent);
            }
        }
    }

    /**
     * 解析样式
     * @param {*} node 
     * @param {*} style 
     */
    var parseStyle = function(node, style, temp){
        switch(node.tagName){
            case "FontName":
                style.fontFamily = node.textContent;
                break;
            case "FontSize":
                style.fontSize = parseInt(node.textContent);
                break;
            case "Align":
                if(node.textContent == "Justify"){
                    style.textAlign = "justify-except-last";
                }else{
                    style.textAlign = (node.textContent + "").toLowerCase();
                }
                break;
            case "VerticalAlign":
                break;
            case "BorderWidth":
                temp.borderWidth = parseFloat(node.textContent);
                break;
            case "BorderTop":
                if(node.textContent == "true"){
                    style.borderTop = style.borderTop ? style.borderTop : {};
                    style.borderTop.width = temp.borderWidth;
                }
                break;
            case "BorderBottom":
                if(node.textContent == "true"){
                    style.borderBottom = style.borderBottom ? style.borderBottom : {};
                    style.borderBottom.width = temp.borderWidth;
                }
                break;
            case "BorderLeft":
                if(node.textContent == "true"){
                    style.borderLeft = style.borderLeft ? style.borderLeft : {};
                    style.borderLeft.width = temp.borderWidth;
                }
                break;
            case "BorderRight":
                if(node.textContent == "true"){
                    style.borderRight = style.borderRight ? style.borderRight : {};
                    style.borderRight.width = temp.borderWidth;
                }
                break;
            case "PaddingLeft":
                style.padding = style.padding ? style.padding : {};
                style.padding.left = parseFloat(node.textContent) / ratioPT;
                break;
            case "PaddingRight":
                style.padding = style.padding ? style.padding : {};
                style.padding.right = parseFloat(node.textContent) / ratioPT;
                break;
            case "PaddingTop":
                style.padding = style.padding ? style.padding : {};
                style.padding.left = parseFloat(node.textContent) / ratioPT;
                break;
            case "PaddingBottom":
                style.padding = style.padding ? style.padding : {};
                style.padding.bottom = parseFloat(node.textContent) / ratioPT;
                break;
            case "Bold":
                style.fontWeight = "bold";
                break;
            case "Underline":
                style.textDecoration = style.textDecoration 
                    ? style.textDecoration + "|underline"
                    : "underline";
                break;
            case "LineSpacingStyle":
                temp.LineSpacingStyle = node.textContent;
                break;
            case "LineSpacing":
                if(temp.LineSpacingStyle == "SpaceMultiple"){
                    style.lineHeight = parseFloat(node.textContent) * 100 + "%";
                }else if(temp.LineSpacingStyle == "SpaceSpecify"){
                    style.lineHeight = node.textContent + "px";
                }
                break;
            case "LeftIndent":
                style.leftWholeIndent = parseFloat(node.textContent) / ratioPT;
                break;
            case "FirstLineIndent":
                style.textIndent = parseFloat(node.textContent) / ratioPT;
                break;
        }
    }
}